package com.fine.hair.applet.wx;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.fine.hair.applet.mapper.UserLoginAccountMapper;
import com.fine.hair.comm.dto.WxRegisterDto;
import com.fine.hair.comm.dto.wx.WxLoginDto;
import com.fine.hair.comm.exception.BusinessException;
import com.fine.hair.comm.model.UserLoginAccount;
import com.fine.hair.comm.pojo.TxErrData;
import com.fine.hair.comm.pojo.wx.*;
import com.fine.hair.comm.utils.ApiResponse;
import com.fine.hair.comm.vo.WxLiteUserInfo;
import com.fine.hair.comm.wx.WxClient;
import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.CharEncoding;
import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.math.BigDecimal;
import java.security.AlgorithmParameters;
import java.security.Key;
import java.security.Security;
import java.text.MessageFormat;

/**
 * @author junelee
 * @date 2020/8/7 14:45
 */
@Slf4j
@Service
public class WxService {

    static {
        try {
            Security.addProvider(new BouncyCastleProvider());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Autowired
    private WxClient wxClient;

    @Autowired
    private UserLoginAccountMapper userLoginAccountMapper;

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private WxLiteProperty wxLiteProperty;


    public WxLiteUserInfo decodeWxLiteUserInfo(WxLoginDto param) {
        // 根据 openId 查找 sessionKey
        LambdaQueryWrapper<UserLoginAccount> uQw = new LambdaQueryWrapper<>();
        uQw.eq(UserLoginAccount::getWxAccount, param.getOpenId());
        UserLoginAccount userLoginAccount = userLoginAccountMapper.selectOne(uQw);
        String sessionKey = userLoginAccount.getSessionKey();
        String decData = decrypt(param.getEncData(), sessionKey,
                param.getIv(), CharEncoding.UTF_8);
        log.info("解密后数据: {}", decData);

        return new Gson().fromJson(decData, WxLiteUserInfo.class);
    }

    private String decrypt(String data, String key, String iv, String encodingFormat) {

        //被加密的数据
        byte[] dataByte = Base64.decodeBase64(data);
        //加密秘钥
        byte[] keyByte = Base64.decodeBase64(key);
        //偏移量
        byte[] ivByte = Base64.decodeBase64(iv);

        try {
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding", "BC");

            Key spec = new SecretKeySpec(keyByte, "AES");

            AlgorithmParameters parameters = AlgorithmParameters.getInstance("AES");
            parameters.init(new IvParameterSpec(ivByte));

            // 初始化
            cipher.init(Cipher.DECRYPT_MODE, spec, parameters);

            byte[] resultByte = cipher.doFinal(dataByte);
            if (null != resultByte && resultByte.length > 0) {
                return new String(resultByte, encodingFormat);
            }
            return null;
        } catch (Exception e) {
            log.error("解密失败. error = {}", e.getMessage(), e);
            throw new BusinessException("请重新登陆");
        }
    }

    public WxLiteUserPhoneNumber decodeWxLitePhoneNumber(WxRegisterDto param) {
        // 根据 openId 查找 sessionKey
        LambdaQueryWrapper<UserLoginAccount> uQw = new LambdaQueryWrapper<>();
        uQw.eq(UserLoginAccount::getWxAccount, param.getOpenId());
        UserLoginAccount userLoginAccount = userLoginAccountMapper.selectOne(uQw);
        String sessionKey = userLoginAccount.getSessionKey();
        String decData = decrypt(param.getEncData(), sessionKey,
                param.getIv(), CharEncoding.UTF_8);
        log.info("解密后数据: {}", decData);

        return new Gson().fromJson(decData, WxLiteUserPhoneNumber.class);

    }

    public WxMpOauthUserAccessToken getWxMpUserOAuth(String code) {
        WxMpOauthUserAccessToken oauthRes = this.wxClient.getWxMpOauthUserToken(code);

        return oauthRes;
    }


    public ApiResponse getWxMpBasicInfo(String accessToken, String openId) {
        WxUserBasicInfoVo wxMpUserBasicInfo = this.wxClient.getWxMpUserBasicInfo(accessToken, openId);
        return ApiResponse.ofSuccess(wxMpUserBasicInfo);
    }


    private void sendWechatMsg(BigDecimal userMoney, Long userId) {
        log.info("执行微信消息通知", userId);
        UserLoginAccount userLoginAccount = userLoginAccountMapper.selectByUserId(userId);

        WxSendData wxSendData = new WxSendData();

        wxSendData.setTemplate_id("K8n5-pfChl9h2s0a_Xnq7P3cGh5-IGpdULwQznn772k");
        wxSendData.setTouser(userLoginAccount.getWxAccount());
        WxSendMsg wxSendMsg = new WxSendMsg();
        WxSendMsg1 wxSendMsg1 = new WxSendMsg1();
        wxSendMsg1.setValue(userMoney + "元");
        WxSendMsg2 wxSendMsg2 = new WxSendMsg2();
        wxSendMsg2.setValue("");
        wxSendMsg.setAmount1(wxSendMsg1);
        wxSendMsg.setThing4(wxSendMsg2);
        wxSendData.setData(wxSendMsg);
        wxSend(wxSendData);
    }

    private static final String URL_WX_LITE_ACCESS_TOKEN = "https://api.weixin.qq" +
            ".com/cgi-bin/token?grant_type=client_credential&appid={0}&secret={1}";
    private static final String URL_SEND = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token={0}";

    public TxErrData wxSend(WxSendData data) {
        String accessTokenUrl = MessageFormat.format(URL_WX_LITE_ACCESS_TOKEN, wxLiteProperty.getAppId(),
                wxLiteProperty.getSecret());
        ResponseEntity<String> res = restTemplate.getForEntity(accessTokenUrl, String.class);

        log.debug("http.status = '{}', body = {}", res.getStatusCode(), res.getBody());
        if (res.getStatusCode() != HttpStatus.OK) {
            log.error("调用微信 URL_WX_LITE_ACCESS_TOKEN 失败. res = {}", res);
            throw new BusinessException("调用微信 URL_WX_LITE_ACCESS_TOKEN 失败");
        }
        System.out.println(res.getBody());

        WxAccessTokenResponse wxAccessTokenResponse = new Gson().fromJson(res.getBody(), WxAccessTokenResponse.class);

        String messageSendUrl = MessageFormat.format(URL_SEND, wxAccessTokenResponse.getAccessToken());
        ResponseEntity<String> result = restTemplate.postForEntity(messageSendUrl, data, String.class);
        System.out.println(result.getBody());
        return new Gson().fromJson(result.getBody(), TxErrData.class);

    }
}
